﻿namespace Home.Services
{
    using System;
    using System.Collections.Generic;
    using System.Globalization;
    using System.IO;
    using System.Linq;
    using System.Security.Cryptography.X509Certificates;
    using System.ServiceModel;
    using System.ServiceModel.Activation;
    using System.ServiceModel.Description;
    using System.ServiceModel.Security;
    using System.Web;
    using System.Web.Configuration;
    using System.Web.Hosting;
    using Home.Configuration;
    using Home.Services.ProductServices;

    public class WebsiteServiceHostFactory : ServiceHostFactory
    {
        private static readonly IReadOnlyDictionary<Type, Type> serviceTypes = new Dictionary<Type, Type>()
        {
            [typeof(ProductService)] = typeof(IProductService)
        };

        public override ServiceHostBase CreateServiceHost(string constructorString, Uri[] baseAddresses)
        {
            return base.CreateServiceHost(constructorString, baseAddresses);
        }

        protected override ServiceHost CreateServiceHost(Type serviceType, Uri[] baseAddresses)
        {
            var host = base.CreateServiceHost(serviceType, baseAddresses);
            var contractType = serviceTypes[serviceType];

            var binding = new WSHttpBinding();
            binding.Security.Mode = SecurityMode.Message;
            binding.Security.Message.ClientCredentialType = MessageCredentialType.Certificate;
            binding.ReaderQuotas.MaxStringContentLength = int.Parse(WebConfigurationManager.AppSettings["home:MaxStringContentLength"], CultureInfo.InvariantCulture);
            binding.MaxReceivedMessageSize = int.Parse(WebConfigurationManager.AppSettings["home:MaxReceivedMessageSize"], CultureInfo.InvariantCulture);
            host.AddServiceEndpoint(contractType, binding, string.Empty);

            var fileName = Path.Combine(HostingEnvironment.MapPath("~/App_Data/website_encryption.pfx"));
            var password = WebConfigurationManager.AppSettings["home:CertificatePassword"];
            var certificate = new X509Certificate2(fileName, password);
            host.Credentials.ServiceCertificate.Certificate = certificate;
            host.Credentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
            host.Credentials.ClientCertificate.Authentication.RevocationMode = X509RevocationMode.NoCheck;

            if (!ConfigurationHelper.IsProductionEnvironment)
            {
                {
                    // add metadata exchange behavior
                    var behavior = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
                    if (behavior != null)
                    {
                        host.Description.Behaviors.Remove(behavior);
                    }
                    behavior = new ServiceMetadataBehavior();
                    behavior.HttpGetEnabled = true;
                    behavior.MetadataExporter.PolicyVersion = PolicyVersion.Policy15;
                    host.Description.Behaviors.Add(behavior);
                    host.AddServiceEndpoint(ServiceMetadataBehavior.MexContractName, MetadataExchangeBindings.CreateMexHttpBinding(), "mex");
                }

                {
                    var behaviors = host.Description.Behaviors.FindAll<ServiceBehaviorAttribute>();
                    foreach (var behavior in behaviors)
                    {
                        behavior.IncludeExceptionDetailInFaults = true;
                    }
                }

                {
                    var behaviors = host.Description.Behaviors.FindAll<ServiceDebugBehavior>();
                    foreach (var behavior in behaviors)
                    {
                        behavior.IncludeExceptionDetailInFaults = true;
                    }
                }
            }

            return host;
        }
    }
}